import re

import FileOps
from Logger import *



def _find_variable_info(map_lines: list, variable_name: str):
    """Find variable info (such as address and size) in gived map file in lines.

    Args:
        map_lines (list): The lines in map file
        variable_str (str): The variable string witch to find in map.

    Returns:
        variable_addr: The variable address if found in map, None otherwize.
        variable_size: The variable size if found in map, None otherwize.
    """
    map_lines = map_lines
    variable_name = variable_name
    VAR_RE_PATTERN = r'^ \.\w+\.{}'.format(variable_name)
    VAR_RE_PATTERN_COMPILED = re.compile(VAR_RE_PATTERN)
    VAR_RE_FULL_PATTERN = VAR_RE_PATTERN + r'\s+0x[0-9a-fA-F]+\s+0x[0-9a-fA-F]+\s+\S+'
    VAR_RE_FULL_PATTERN_COMPILED = re.compile(VAR_RE_FULL_PATTERN)
    found_variable_in_map = False
    for index in range(0, len(map_lines)):
        line = map_lines[index]
        if VAR_RE_PATTERN_COMPILED.match(line):
            found_variable_in_map = True
            if not VAR_RE_FULL_PATTERN_COMPILED.match(line):
                line = line + map_lines[index + 1]
            break

    if found_variable_in_map:
        split_line_list = re.split(r' +', line.strip())
        variable_addr = split_line_list[1]
        variable_size = split_line_list[2]
        if (variable_addr[0:2].lower() != '0x') or (variable_size[0:2].lower() != '0x'):
            found_variable_in_map = False

    if not found_variable_in_map:
        LOG(LEVEL_WARN, 'Cannot find the variable you want, Please check.')
        return None, None
    LOG(LEVEL_INFO, 'var:[{}], addr: [{}], size: [{}]'.format(variable_name, variable_addr, variable_size))
    return variable_addr, variable_size


def get_variable_info(filepath: str, variable_name: str):
    lines = FileOps.read(filepath, "r", need_split=True, encoding="utf8")
    if not lines:
        return None
    addr, size = _find_variable_info(lines, variable_name)
    if addr and size:
        return addr, size
    else:
        return None


def get_bin_start_addr(filepath: str):
    map_lines = FileOps.read(filepath, "r", need_split=True, encoding="utf8")
    if not map_lines:
        return None
    SECTION_RE_PATTERN = r'^\.\w+'
    SECTION_RE_PATTERN_COMPILED = re.compile(SECTION_RE_PATTERN)
    SECTION_RE_FULL_PATTERN = SECTION_RE_PATTERN + r'\s+0x[0-9a-fA-F]+\s+0x[0-9a-fA-F]'
    SECTION_RE_FULL_PATTERN_COMPILED = re.compile(SECTION_RE_FULL_PATTERN)
    found_fist_section = False
    bin_start_addr = None
    for index in range(0, len(map_lines)):
        line = map_lines[index]
        line_next = map_lines[index + 1]
        if SECTION_RE_PATTERN_COMPILED.match(line):
            found_fist_section = True
            if not SECTION_RE_FULL_PATTERN_COMPILED.match(line):
                line = line + line_next
            break

    if found_fist_section:
        split_line_list = re.split(r' +', line.strip())
        bin_start_addr = split_line_list[1]
        if (bin_start_addr[0:2].lower() != '0x'):
            found_fist_section = False

    if not found_fist_section:
        LOG(LEVEL_WARN, 'Cannot find the app bin start address in map file, Please check.')
        return None
    LOG(LEVEL_INFO, 'section name: [{}], addr: [{}]'.format(split_line_list[0], bin_start_addr))
    return bin_start_addr